#include "perceptron.h"

#include <fstream>
#include <iostream>
using namespace std;

perceptron::perceptron(int eN, int fN, float ETA)
{
	example_num = eN;
	feature_num = fN;
	eta = ETA;
	
	w = new float[feature_num];			// set initial weighted vector to zeros
	for(int i = 0; i < example_num; i++)
	{
		w[i] = 0.0;
	}
	b = 0.0;	// set initial bias to zero
	
	x = new float*[example_num];		// allocate space for feature matrix
	for(int i = 0; i < example_num; i++)
	{
		x[i] = new float[feature_num];
	}
	
	y = new int[example_num];	// allocate space for output vector
}

perceptron::~perceptron()
{
	delete []w;
	delete []y;
	for(int i = 0; i < example_num; i++)
	{
		delete []x[i];
	}
	delete []x;
}

void perceptron::read_training_set(char* filename)
{
	ifstream training_set_file;
	training_set_file.open(filename, fstream::in);
	if(training_set_file.fail())
	{
		cout << filename << "not exists!" << endl;
		training_set_file.close();
	}
	else
	{
		int line_num = 0;
		while(!training_set_file.eof())
		{
			for(int i = 0; i < feature_num; i++)
			{
				training_set_file >> x[line_num][i];
			}
			training_set_file >> y[line_num];
			
			line_num++;
		}
		training_set_file.close();
	}
}

void perceptron::test(char* test_set_filename, char* test_result_filename)
{
	ifstream test_set_file;
	ofstream test_result_file;
	test_set_file.open(test_set_filename, fstream::in);
	test_result_file.open(test_result_filename, fstream::out | fstream::trunc);
	if(test_set_file.fail())
	{
		cout << test_set_filename << "not exist!" << endl;
		test_set_file.close();
	}
	else if(test_result_file.fail())
	{
		cout << test_result_filename << "not exist!" << endl;
		test_result_file.close();
	}
	else
	{
		float *t = new float[feature_num];
		float r;
		while(!test_set_file.eof())
		{
			r = 0.0;
			for(int i = 0; i < feature_num; i++)
			{
				test_set_file >> t[i];
			}
			for(int i = 0; i < feature_num; i++)
			{
				r += w[i] * t[i];
			}
			r += b;
			// sign function
			if(r >= 0.0)
			{
				test_result_file << "1" << endl;
			}
			else
			{
				test_result_file << "-1" << endl;
			}
		}
		test_set_file.close();
		test_result_file.close();
	}
}

void perceptron::training()
{
	float tmp;
	for(int i = 0; i < example_num; i++)
	{
		tmp = 0.0;
		for(int j = 0; j < feature_num; j++)
		{
			tmp += w[j] * x[i][j];
		}
		tmp += b;
		if(y[i] * tmp <= 0.0)
		{
			// update weighted vector and bias
			for(int j = 0; j < feature_num; j++)
			{
				w[j] += eta * y[i] * x[i][j];  
			}
			b += eta * y[i];
			i = 0;	// test again from the first example
		}
	}
}


void perceptron::print_model()
{
	for(int i = 0; i < feature_num; i++)
	{
		cout << w[i] << " ";
	}
	cout << endl << b << endl;
}
